package com.avo.ramcache.orm.impl.m2s;

import com.avo.ramcache.constant.SymbolConstant;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.query.NativeQuery;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate5.HibernateTemplate;

import java.util.List;

@SuppressWarnings({"rawtypes", "unchecked"})
public class ServerHibernateTemplate extends HibernateTemplate {

    public ServerHibernateTemplate(SessionFactory sessionFactory) {
        super(sessionFactory);
        setCheckWriteOperations(false);
    }

    public <T> List<T> S2SListByServer(int server, Class<T> clz, String queryname, Object[] querynameValue) {
        return S2SListByServer(server, clz, 0, 0, queryname, querynameValue);
    }

    public <T> List<T> S2SListByServer(int server, Class<T> clz, int from, int to, String queryname, Object[] querynameValue) {
        return executeWithNativeSession(session -> {
            String queryString = session.getNamedQuery(queryname).getQueryString();
            String newSql;
            if (queryString.indexOf("where") > 0) {
                newSql = queryString.replace("where", "where server = " + server + "and");
            } else {
                String simpleName = queryname.split("\\.")[0];
                newSql = queryString.replace(simpleName, simpleName + " where server = " + server);
            }
            NativeQuery query = session.createNativeQuery(newSql);
            if (from > 0 && to > 0) {
                query.setFirstResult(from);
                query.setMaxResults(to);
            }
            if (clz != null) {
                query.addEntity(clz);
            }
            prepareQuery(query);
            if (querynameValue != null) {
                for (int i = 0; i < querynameValue.length; i++) {
                    query.setParameter(i, querynameValue[i]);
                }
            }
            return query.list();
        });
    }

    public <T> List<T> M2SListByServer(int server, Class<T> clz, String queryname, Object[] querynameValue) {
        return M2SListByTableName(server, 0, 0, clz, queryname, querynameValue);
    }

    public <T> List<T> M2SListByTableName(int server, int from, int to, Class<T> clz, String queryname, Object[] querynameValue) {
        return executeWithNativeSession(session -> {
            String queryString = session.getNamedQuery(queryname).getQueryString();
            String tableName = queryname.split("\\.")[0];
            String newTableName = M2SHibernateHelper.tableName(server, tableName);
            String newSql;
            if (queryString.indexOf("where") > 0) {
                newSql = queryString.replace(tableName, newTableName);
                newSql = newSql.replace("where", " where expire != 1 and");
            } else {
                newSql = queryString.replace(tableName, newTableName + " where expire != 1 ");
            }
            NativeQuery query = session.createNativeQuery(newSql);
            if (from > 0 && to > 0) {
                query.setFirstResult(from);
                query.setMaxResults(to);
            }
            if (clz != null) {
                query.addEntity(clz);
            }
            prepareQuery(query);
            if (querynameValue != null) {
                for (int i = 0; i < querynameValue.length; i++) {
                    query.setParameter(i, querynameValue[i]);
                }
            }
            return query.list();
        });
    }

    public Integer M2SExecuteByServer(int server, String queryname, Object[] querynameParams) {
        return executeWithNativeSession(session -> {
            String queryString = session.getNamedQuery(queryname).getQueryString();
            String tableName = queryname.split("\\.")[0];
            String newTableName = M2SHibernateHelper.tableName(server, tableName);
            String newSql = queryString.replace(tableName, newTableName);
            NativeQuery query = session.createNativeQuery(newSql);
            prepareQuery(query);
            if (querynameParams != null) {
                for (int i = 0; i < querynameParams.length; i++) {
                    query.setParameter(i, querynameParams[i]);
                }
            }
            return query.executeUpdate();
        });
    }

    public int sql(String newSql) {
        return executeWithNativeSession(session -> {
            NativeQuery query = session.createNativeQuery(newSql);
            prepareQuery(query);
            return query.executeUpdate();
        });
    }

    public <T> List<T> allByServer(int server, Class<T> clz) {
        return executeWithNativeSession(session -> {
            String sql = "select * from " + M2SHibernateHelper.getDBName(server) + SymbolConstant.SPOT + clz.getSimpleName();
            NativeQuery query = session.createNativeQuery(sql);
            query.addEntity(clz);
            prepareQuery(query);
            return query.list();
        });
    }

    public void update(final Object entity, final LockMode lockMode) throws DataAccessException {
        this.executeWithNativeSession(session -> {
            Transaction tx = session.beginTransaction();
            session.update(entity);
            if (lockMode != null) {
                session.buildLockRequest(new LockOptions(lockMode)).lock(entity);
            }
            session.flush();
            tx.commit();
            return null;
        });
    }

    public void saveOrUpdate(final Object entity) throws DataAccessException {
        this.executeWithNativeSession(session -> {
            Transaction tx = session.beginTransaction();
            session.saveOrUpdate(entity);
            session.flush();
            tx.commit();
            return null;
        });
    }
}
